package cn.iocoder.an.module.business.service.reportview;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.an.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.an.module.business.dal.dataobject.reportview.ReportTreeNode;
import cn.iocoder.an.module.system.dal.dataobject.dept.DeptDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.an.module.business.controller.admin.reportview.vo.*;
import cn.iocoder.an.module.business.dal.dataobject.reportview.ReportViewDO;
import cn.iocoder.an.framework.common.pojo.PageResult;
import cn.iocoder.an.framework.common.pojo.PageParam;
import cn.iocoder.an.framework.common.util.object.BeanUtils;

import cn.iocoder.an.module.business.dal.mysql.reportview.ReportViewMapper;

import static cn.iocoder.an.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.an.module.business.enums.ErrorCodeConstants.*;

/**
 * 报表汇总 Service 实现类
 *
 * @author zzy
 */
@Service
@Validated
public class ReportViewServiceImpl implements ReportViewService {

    @Resource
    private ReportViewMapper reportViewMapper;

    @Override
    public Long createReportView(ReportViewDO reportView) {
        if (reportView.getParentId() == null) {
            reportView.setParentId(reportView.PARENT_ID_ROOT);
        }
        // 校验父部门的有效性
        validateParentReport(null, reportView.getParentId());
        // 校验部门名的唯一性
        validateReportNameUnique(null, reportView.getParentId(), reportView.getName());

        // 插入部门
        reportView.clean(); // 清理掉创建、更新时间等相关属性值
        reportViewMapper.insert(reportView);
        return reportView.getId();
    }

    @Override
    public void updateReportView(ReportViewDO reportView) {
        if (reportView.getParentId() == null) {
            reportView.setParentId(ReportViewDO.PARENT_ID_ROOT);
        }
        // 校验自己存在
        validateReportViewExists(reportView.getId());
        // 校验父级的有效性
        validateParentReport(reportView.getId(), reportView.getParentId());
        // 校验名称的唯一性
//        validateReportNameUnique(reportView.getId(), reportView.getParentId(), reportView.getName());
        // 更新
        reportViewMapper.updateById(reportView);
        // 更新
//        reportView.clean(); // 清理掉创建、更新时间等相关属性值
//        reportViewMapper.updateById(reportView);
    }

    @Override
    public void deleteReportView(Long id) {
        // 校验存在
        validateReportViewExists(id);
        // 校验是否有子部门
        if (reportViewMapper.selectCountByParentId(id) > 0) {
            throw exception(REPORT_EXITS_CHILDREN);
        }
        // 删除部门
        reportViewMapper.deleteById(id);
    }

    @Override
        public void deleteReportViewListByIds(List<Long> ids) {
        // 删除
        reportViewMapper.deleteByIds(ids);
        }


    private void validateReportViewExists(Long id) {
        if (reportViewMapper.selectById(id) == null) {
            throw exception(REPORT_VIEW_NOT_EXISTS);
        }
    }

    @Override
    public ReportViewDO getReportView(Long id) {
        return reportViewMapper.selectById(id);
    }

    @Override
    public PageResult<ReportViewDO> getReportViewPage(ReportViewPageReqVO pageReqVO) {
        return reportViewMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ReportViewDO> getReportList() {
        List<ReportViewDO> list = reportViewMapper.selectList();
        list.sort(Comparator.comparing(ReportViewDO::getSort));
        return list;
    }

    @VisibleForTesting
    void validateParentReport(Long id, Long parentId) {
        if (parentId == null || ReportViewDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父部门
        if (Objects.equals(id, parentId)) {
            throw exception(REPORT_PARENT_ERROR);
        }
        // 2. 父部门不存在
        ReportViewDO parentReport = reportViewMapper.selectById(parentId);
        if (parentReport == null) {
            throw exception(REPORT_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父部门，如果父部门是自己的子部门，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentReport.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(REPORT_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父部门
            if (parentId == null || ReportViewDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentReport = reportViewMapper.selectById(parentId);
            if (parentReport == null) {
                break;
            }
        }
    }

    @VisibleForTesting
    void validateReportNameUnique(Long id, Long parentId, String name) {
        ReportViewDO dept = reportViewMapper.selectByParentIdAndName(parentId, name);
        if (dept == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的部门
        if (id == null) {
            throw exception(REPORT_NAME_DUPLICATE);
        }
        if (ObjectUtil.notEqual(dept.getId(), id)) {
            throw exception(REPORT_NAME_DUPLICATE);
        }
    }

    /**
     * 查询树结构
     * @param reqVO 名称(模糊查询)
     * @return 树结构列表，模糊查询时返回平铺列表
     */
//    @Override
    public List<Tree<Long>> selectTreeback(ReportViewPageReqVO reqVO) {
        List<ReportViewDO> deptAllList = new ArrayList<>();
        boolean flag = false;
        if (reqVO.getParentId() != null) {
            flag = true;

            LambdaQueryWrapperX<ReportViewDO> pa = new LambdaQueryWrapperX<>();
            pa.eq(ReportViewDO::getParentId, 0L);
            ReportViewDO first = reportViewMapper.selectList(pa).getFirst();

            //循环取子ID
            deptAllList = getChildDeptList(Collections.singleton(reqVO.getParentId()));
            deptAllList.add(first);
        }else{
            flag = false;
            // 查询全部
            deptAllList = reportViewMapper
                    .selectList(Wrappers.<ReportViewDO>lambdaQuery().like(StrUtil.isNotBlank(reqVO.getName()), ReportViewDO::getName, reqVO.getName()));
        }

        // 权限内
        List<ReportTreeNode> collect = deptAllList.stream()
                .filter(dept -> dept.getId().intValue() != dept.getParentId())
                .sorted(Comparator.comparingInt(ReportViewDO::getSort))
                .map(dept -> {
                    ReportTreeNode treeNode = new ReportTreeNode();
                    treeNode.setId(dept.getId());
                    treeNode.setParentId(dept.getParentId());
                    treeNode.setName(dept.getName());
                    treeNode.setWeight(dept.getSort());
                    treeNode.setUrl(dept.getUrl());
                    treeNode.setIcon(dept.getIcon());
                    treeNode.setColor(dept.getColor());
                    treeNode.setTitle(dept.getTitle());
                    return treeNode;
                })
                .collect(Collectors.toList());

        // 模糊查询 不组装树结构 直接返回 表格方便编辑
        if (StrUtil.isNotBlank(reqVO.getName()) && !flag) {
            return collect.stream().map(node -> {
                Tree<Long> tree = new Tree<>();
                tree.putAll(node.getExtra());
                org.springframework.beans.BeanUtils.copyProperties(node, tree);
                return tree;
            }).collect(Collectors.toList());
        }
        Long rootId = (reqVO.getParentId() != null) ? reqVO.getParentId() : 0L;
        return TreeUtil.build(collect, rootId,
                (treeNode, tree) -> {
                    tree.setId((Long) treeNode.getId());
                    tree.setParentId((Long) treeNode.getParentId());
                    tree.setName(treeNode.getName());
                    tree.setWeight(treeNode.getWeight());
                    // 其他属性拷贝
                    tree.putExtra("url", treeNode.getUrl());
                    tree.putExtra("icon", treeNode.getIcon());
                    tree.putExtra("title", treeNode.getTitle());
                    tree.putExtra("color", treeNode.getColor());
                });

    }

    @Override
    public List<Tree<Long>> selectTree(ReportViewPageReqVO reqVO) {
        List<ReportViewDO> deptAllList = new ArrayList<>();

        if (reqVO.getParentId() != null) {
            // 1. 获取从 reqVO.getParentId() 向上的完整路径（直到根）
            Set<Long> ancestorIds = getAncestors(reqVO.getParentId()); // 包含自己和祖先
            // 2. 获取 reqVO.getParentId() 及其所有后代
            List<ReportViewDO> descendants = getChildDeptList(Collections.singleton(reqVO.getParentId()));
            // 3. 查询这些节点的完整信息（包括祖先）
            LambdaQueryWrapperX<ReportViewDO> wrapper = new LambdaQueryWrapperX<>();
            wrapper.in(ReportViewDO::getId, ancestorIds)
                    .or()
                    .in(!descendants.isEmpty(), ReportViewDO::getId, descendants.stream().map(ReportViewDO::getId).collect(Collectors.toSet()));
            deptAllList = reportViewMapper.selectList(wrapper);

            // 确保包含真正的根节点（id=100）—— 如果系统有固定根，可硬编码
            // 或通过 parentId=0 查询
            LambdaQueryWrapperX<ReportViewDO> rootWrapper = new LambdaQueryWrapperX<>();
            rootWrapper.eq(ReportViewDO::getParentId, 0L);
            ReportViewDO root = reportViewMapper.selectOne(rootWrapper);
            if (root != null && !deptAllList.contains(root)) {
                deptAllList.add(root);
            }
        } else {
            // 全量查询（模糊搜索等）
            deptAllList = reportViewMapper.selectList(
                    Wrappers.<ReportViewDO>lambdaQuery()
                            .like(StrUtil.isNotBlank(reqVO.getName()), ReportViewDO::getName, reqVO.getName())
            );
        }

        // 转换为 TreeNode 列表
        List<ReportTreeNode> collect = deptAllList.stream()
                .filter(dept -> dept.getId().intValue() != dept.getParentId()) // 避免自环
                .sorted(Comparator.comparingInt(ReportViewDO::getSort))
                .map(dept -> {
                    ReportTreeNode node = new ReportTreeNode();
                    node.setId(dept.getId());
                    node.setParentId(dept.getParentId());
                    node.setName(dept.getName());
                    node.setWeight(dept.getSort());
                    node.setUrl(dept.getUrl());
                    node.setIcon(dept.getIcon());
                    node.setColor(dept.getColor());
                    node.setTitle(dept.getTitle());
                    return node;
                })
                .collect(Collectors.toList());

        // 模糊查询不建树
        if (StrUtil.isNotBlank(reqVO.getName()) && reqVO.getParentId() == null) {
            return collect.stream().map(node -> {
                Tree<Long> tree = new Tree<>();
                BeanUtils.copyProperties(node, tree);
                tree.putExtra("url", node.getUrl());
                tree.putExtra("icon", node.getIcon());
                tree.putExtra("title", node.getTitle());
                tree.putExtra("color", node.getColor());
                return tree;
            }).collect(Collectors.toList());
        }

        // 构建树：以真正的根（parentId=0）为起点
        Long rootId = 0L; // 固定根节点 ID
        return TreeUtil.build(collect, rootId, (treeNode, tree) -> {
            tree.setId((Long) treeNode.getId());
            tree.setParentId((Long) treeNode.getParentId());
            tree.setName(treeNode.getName());
            tree.setWeight(treeNode.getWeight());
            tree.putExtra("url", treeNode.getUrl());
            tree.putExtra("icon", treeNode.getIcon());
            tree.putExtra("title", treeNode.getTitle());
            tree.putExtra("color", treeNode.getColor());
        });
    }


    private Set<Long> getAncestors(Long startId) {
        Set<Long> ancestors = new LinkedHashSet<>(); // 保持顺序
        Long current = startId;
        while (current != null && current != 0) {
            ancestors.add(current);
            // 查询 current 的父节点
            ReportViewDO parent = reportViewMapper.selectById(current);
            if (parent == null || parent.getParentId() == null) break;
            current = parent.getParentId();
        }
        // 确保包含根节点（parentId=0 的那个）
        LambdaQueryWrapperX<ReportViewDO> rootQw = new LambdaQueryWrapperX<>();
        rootQw.eq(ReportViewDO::getParentId, 0L);
        ReportViewDO root = reportViewMapper.selectOne(rootQw);
        if (root != null) {
            ancestors.add(root.getId());
        }
        return ancestors;
    }


    public List<ReportViewDO> getChildDeptList(Collection<Long> ids) {
        List<ReportViewDO> children = new LinkedList<>();
        // 遍历每一层
        Collection<Long> parentIds = ids;
        for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下，存在死循环
            // 查询当前层，所有的子部门
            LambdaQueryWrapperX<ReportViewDO> queryWrapperX = new LambdaQueryWrapperX<>();
            queryWrapperX.in(ReportViewDO::getParentId, parentIds);
            List<ReportViewDO> depts = reportViewMapper.selectList(queryWrapperX);
            // 1. 如果没有子部门，则结束遍历
            if (CollUtil.isEmpty(depts)) {
                break;
            }
            // 2. 如果有子部门，继续遍历
            children.addAll(depts);
            parentIds = convertSet(depts, ReportViewDO::getId);
        }
        return children;
    }



}